package com.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.constant.UserConstant;
import com.domain.RefreshTokenDetail;
import com.domain.User;
import com.domain.UserInfo;
import com.dto.PageResult;
import com.exception.ConditionException;
import com.mapper.UserDao;
import com.util.MD5Util;
import com.util.RSAUtil;
import com.util.TokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class UserServiceImpl {

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserAuthServiceImpl userAuthService;

    /**
     * 用户注册
     */
    @Transactional
    public void register(User user) {
        String phone = user.getPhone();
        if (StringUtils.isBlank(phone) || StringUtils.isEmpty(phone)) {
            throw new ConditionException("手机号不能为空");
        }
        User dbUser = userDao.getUserByPhone(phone);
        if (dbUser != null) {
            throw new ConditionException("该手机号已经注册！");
        }
        Date now = new Date();
        String salt = String.valueOf(now.getTime());
        String password = user.getPassword();
        String rawPassword;
        try {
            //解密前端传来的密码。翻译成明文
            rawPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败");
        }
        //把明文加密成MD5密码存入数据库
        String md5Password = MD5Util.sign(rawPassword, salt, "UTF-8");
        user.setSalt(salt);
        user.setPassword(md5Password);
        user.setCreateTime(now);
        userDao.addUser(user);

        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNick(UserConstant.DEFAULT_NICK);
        userInfo.setBirth(UserConstant.DEFAULT_BIRTH);
        userInfo.setGender(UserConstant.GENDER_MALE);
        userInfo.setCreateTime(now);
        userDao.addUserInfo(userInfo);
        //给新用户设置默认角色
        userAuthService.addUserDefaultRole(user.getId());
    }

    /**
     * 用户登录（支持手机号登录和邮箱登录，两者的密码相同）
     */
    public String login(User user) throws Exception {
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if (StringUtils.isBlank(phone) && StringUtils.isEmpty(phone)
                && StringUtils.isBlank(email) && StringUtils.isEmpty(email)) {
            throw new ConditionException("手机号或邮箱不能为空");
        }

        //判断用户是否存在
        User dbUser = userDao.getUserByPhoneOrEmail(phone, email);
        if (dbUser == null) {
            throw new ConditionException("当前用户不存在");
        }
        //解密前端传来的密码
        String password = user.getPassword(); //此时的password是密文形式
        String rawPassword;
        try {
            rawPassword = RSAUtil.decrypt(password); //解密前端传来的密码，用rawPassword接收解密后的密码
        } catch (Exception e) {
            throw new ConditionException("密码解密失败");
        }
        //解密出数据库的md5密文
        String md5Password = MD5Util.sign(rawPassword, dbUser.getSalt(), "UTF-8");
        //解密的密文和数据库的密文对比
        if (!md5Password.equals(dbUser.getPassword())) {
            throw new ConditionException("密码错误");
        }
        //返回token令牌
        return TokenUtil.generateToken(dbUser.getId());
    }

    /**
     * 获取用户全部信息
     */
    public User getUserAndInfoByUserId(Long userId) {
        User user = userDao.getUserByUserId(userId);
        UserInfo userInfo = userDao.getUserInfoByUserId(userId);
        user.setUserInfo(userInfo);
        return user;
    }

    /**
     * 修改用户信息
     */
    @Transactional
    public void updateUserInfos(UserInfo userInfo) {
        userInfo.setUpdateTime(new Date());
        userDao.updateUserInfos(userInfo);
    }

    /**
     * 修改用户的 phone、email以及password三个字段
     */
    @Transactional
    public void updateUsers(User user) throws Exception {
        Long userId = user.getId();
        User dbUser = userDao.getUserByUserId(userId);
        if (dbUser == null) {
            throw new ConditionException("该用户不存在");
        }
        String password = user.getPassword();
        if (StringUtils.isEmpty(password) || StringUtils.isBlank(password)) {
            throw new ConditionException("密码不能为空");
        }
        String rawPassword = RSAUtil.decrypt(password); //对前端密码进行RSA解密
        String md5Password = MD5Util.sign(rawPassword, dbUser.getSalt(), "UTF-8"); //对密码进行MD5加密
        user.setPassword(md5Password); //更新密码
        user.setUpdateTime(new Date());
        userDao.updateUsers(user); //数据库更新记录
    }


    /**
     * 获取用户信息
     */
    public User getUserById(Long userId) {
        return userDao.getUserByUserId(userId);
    }

    /**
     * 批量获取用户信息
     */
    public List<UserInfo> getUserInfoByUserIds(Set<Long> userIdList) {
        return userDao.getUserInfoByUserIds(userIdList);
    }

    /**
     * 分页获取用户信息列表
     */
    public PageResult<UserInfo> pageListUserInfos(JSONObject params) {
        Integer pageNum = params.getInteger("pageNum");
        Integer pageSize = params.getInteger("pageSize");
        params.put("start", (pageNum - 1) * pageSize);
        params.put("limit", pageSize);
        Integer total = userDao.pageCountUserInfos(params);
        List<UserInfo> list = new ArrayList<>();
        if (total > 0) {
            list = userDao.pageListUserInfos(params);
        }
        return new PageResult<>(total, list);
    }


    @Transactional
    public Map<String, Object> loginForDts(User user) throws Exception {
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if (StringUtils.isBlank(phone) && StringUtils.isEmpty(phone)
                && StringUtils.isBlank(email) && StringUtils.isEmpty(email)) {
            throw new ConditionException("手机号或邮箱不能为空");
        }
        //判断用户是否存在
        User dbUser = userDao.getUserByPhoneOrEmail(phone, email);
        if (dbUser == null) {
            throw new ConditionException("当前用户不存在");
        }
        //解密前端传来的密码
        String password = user.getPassword(); //此时的password是密文形式
        String rawPassword;
        try {
            rawPassword = RSAUtil.decrypt(password); //解密前端传来的密码，用rawPassword接收解密后的密码
        } catch (Exception e) {
            throw new ConditionException("密码解密失败");
        }
        //解密出数据库的md5密文
        String md5Password = MD5Util.sign(rawPassword, dbUser.getSalt(), "UTF-8");
        //解密的密文和数据库的密文对比
        if (!md5Password.equals(dbUser.getPassword())) {
            throw new ConditionException("密码错误");
        }

        String accessToken = TokenUtil.generateToken(dbUser.getId());
        String refreshToken = TokenUtil.generateRefreshToken(dbUser.getId());
        //保存refreshToken到数据库，(采用先删除后添加)
        userDao.deleteRefreshToken(refreshToken, dbUser.getId());
        userDao.addRefreshToken(refreshToken, dbUser.getId(), new Date());
        Map<String, Object> result = new HashMap<>(2);
        result.put("accessToken", accessToken);
        result.put("refreshToken", refreshToken);
        return result;
    }


    public void logout(String refreshToken, Long userId) {
        userDao.deleteRefreshToken(refreshToken, userId);
    }


    public String refreshAccessToken(String refreshToken) throws Exception {
        RefreshTokenDetail refreshTokenDetail = userDao.getRefreshTokenDetail(refreshToken);
        if (refreshTokenDetail == null) {
            throw new ConditionException("555", "token过期!");
        }
        Long userId = refreshTokenDetail.getUserId();
        return TokenUtil.generateToken(userId);
    }


    public List<UserInfo> batchGetUserInfoByUserIds(Set<Long> userIdList) {
        return userDao.batchGetUserInfoByUserIds(userIdList);
    }

    public String getRefreshTokenByUserId(Long userId) {
        return userDao.getRefreshTokenByUserId(userId);
    }
}
